﻿using System;
using System.Linq;
using System.IO;

namespace etdc
{
    internal class Program
    {
        // ET1 Decryptor
        // (c) C.c 2011

        private static void Usage()
        {
            Console.WriteLine("etdc, the ET1 Decryptor by C.c 2011\n");
            Console.WriteLine("Usage: etdc -option [file] [file] [file/bytes]");
            Console.WriteLine("Available options:");
            Console.WriteLine("   -e [TS1 File] [FDB file] [Output Raw Keyfile]");
            Console.WriteLine("     Extract raw keyfile. The keyfile must be edited to use");
            Console.WriteLine("     as key for decryption. You must  figure out repeating ");
            Console.WriteLine("     part (something like first 10 bytes) and cut it by yourself.");
            Console.WriteLine("     Hex editor may be very helpfull =)\n");
            Console.WriteLine("   -d [TS1 File] [Keyfile] [Output FDB File]");
            Console.WriteLine("     Decrypt database using specified keyfile as key.\n");
            Console.WriteLine("   -g [Keyfile] [Long Keyfile] [Bytes Count]");
            Console.WriteLine("     (DEBUG OPTION)Generate long (length = Bytes Count) keyfile");
            Console.WriteLine("     based on keyfile.\n");
            Console.WriteLine("   -x [File 1] [File 2] [Output File]");
            Console.WriteLine("     (DEBUG OPTION)XOR input files\n");
            Console.WriteLine("   -c [source] [keyfile] [output]");
            Console.WriteLine("     Encrypt FDB to ET1\n");

            Environment.Exit(0);
        }

        private static void ExtractKeyFile(string encryptedFile, string sourceFile, string keyFile)
        {
            try
            {
                var encrypted = Ts1.Load(encryptedFile).GetBodyData();
                var source = File.ReadAllBytes(sourceFile);

                if (encrypted.Length != source.Length)
                    throw new Exception("The source and encrypted file lengths doesn't match");

                File.WriteAllBytes(keyFile, encrypted.XorWith(source));
                Console.WriteLine("Raw keyfile extracted.");

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Environment.Exit(1);
            }
        }

        private static void XorFiles(string iFile1, string iFile2, string outputFile)
        {
            try
            {
                var file1 = File.ReadAllBytes(iFile1);
                var file2 = File.ReadAllBytes(iFile2);

                if (file1.Length != file2.Length)
                    throw new Exception("The files lengths doesn't match");

                File.WriteAllBytes(outputFile, file1.XorWith(file2));
                Console.WriteLine("XOR done.");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Environment.Exit(1);
            }
        }

        private static void DecryptDb(string encryptedFile, string keyFile, string outputFile)
        {
            try
            {
                File.WriteAllBytes(outputFile, Ts1.Load(encryptedFile).Decrypt(File.ReadAllBytes(keyFile)));
                Console.WriteLine("TS1 file decrypted.");

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Environment.Exit(1);
            }
        }

        private static void GenerateLongKey(string keyFile, string output, string strLength)
        {
            try
            {
                var length = int.Parse(strLength);
                var key = File.ReadAllBytes(keyFile);

                File.WriteAllBytes(output, KeyGenerator.Generate(key).Take(length).ToArray());
                Console.WriteLine("Keyfile generated.");

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Environment.Exit(1);
            }
        }

        private static void EncryptDb(string keyFile, string source, string output)
        {
            try
            {
                Ts1.Encrypt(File.ReadAllBytes(source), File.ReadAllBytes(keyFile)).Save(output);
                Console.WriteLine("TS1 file encrypted");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Environment.Exit(1);
            }
        }

        private static void Main(string[] args)
        {
            if (args.Length == 0 || args[0][0] != '-' || args[0].Length != 2)
            {
                Usage();
            }

            var mode = args[0].Substring(1).ToLower()[0];
            switch (mode)
            {
                case 'e':
                    if (args.Length < 4) Usage();
                    ExtractKeyFile(args[1], args[2], args[3]);
                    break;

                case 'd':
                    if (args.Length < 4) Usage();
                    DecryptDb(args[1], args[2], args[3]);

                    break;
                case 'g':
                    if (args.Length < 4) Usage();
                    GenerateLongKey(args[1], args[2], args[3]);
                    break;

                case 'x':
                    if (args.Length < 4) Usage();
                    XorFiles(args[1], args[2], args[3]);
                    break;

                case 'c':
                    if (args.Length < 4) Usage();
                    EncryptDb(args[1], args[2], args[3]);
                    break;
            }
        }
    }
}